﻿using System.Windows.Shapes;
using System.Windows;
using System.Collections.ObjectModel;
using DeepEarth.Map.Core;
using System;
using System.Windows.Media;
using DeepEarth.Core;
namespace DeepEarth.Toolkit.Geometry
{
    /// <summary>
    /// Creates a shape based on a collection of Locations without using a map
    /// No projection will be applied
    /// </summary>
    public class LocationPath : Path
    {
        public static readonly DependencyProperty LocationsProperty =
            DependencyProperty.Register("Locations", typeof(ObservableCollection<Location>), typeof(LocationPath), new PropertyMetadata(LocationsChangedHandler));
        
        public ObservableCollection<Location> Locations
        {
            get { return (ObservableCollection<Location>)GetValue(LocationsProperty); }
            set { SetValue(LocationsProperty, value); }
        }

        private static void LocationsChangedHandler(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            LocationPath self = sender as LocationPath;

            if (args.OldValue != null)
            {
                ObservableCollection<Location> oldLocations = args.OldValue as ObservableCollection<Location>;
                oldLocations.CollectionChanged -= self.locations_CollectionChanged;
            }

            if (args.NewValue != null)
            {
                ObservableCollection<Location> newLocations = args.NewValue as ObservableCollection<Location>;
                newLocations.CollectionChanged += self.locations_CollectionChanged;

                self.locations_CollectionChanged(null, null);
            }
            else
            {
                self.PathData = null;
            }
        }

        void locations_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            this.GeneratePath(this.Width, this.Height);
        }

        private LocationRectangle bounds;

        public PathGeometry PathData
        {
            get { return (PathGeometry)this.Data; }
            set
            {
                this.Data = value;
            }
        }

        private void GeneratePath(double width, double height)
        {
            DetermineBounds();

            double aspectWidth = width;
            double aspectHeight = height;

            double aspectRatio = bounds.Width / bounds.Height;

            if (aspectRatio > 1)
            {
                //wide
                aspectHeight = width / aspectRatio;

                if (aspectHeight > height)
                {
                    aspectHeight = height;
                    aspectWidth = aspectHeight * aspectRatio;
                }
            }
            else
            {
                //tall
                aspectWidth = height * aspectRatio;

                if (aspectWidth > width)
                {
                    aspectWidth = width;
                    aspectHeight = aspectWidth / aspectRatio;
                }
            }


            PathGeometry pathData = new PathGeometry();
            var pf = new PathFigure();
            int idx = 0;

            //Create an optimized calculation for the points in the loop.
            if (this.Locations != null && this.Locations.Count > 0 && this.bounds != null)
            {
                foreach (Location location in this.Locations)
                {
                    Point relativeLocation = new Point
                    {
                        X = Math.Abs(location.Longitude - bounds.West),
                        Y = Math.Abs(location.Latitude - bounds.North)
                    };

                    //Add pixels relative to Layer size.
                    Point pixel = new Point();

                    pixel.X = (relativeLocation.X / bounds.Width) * aspectWidth;
                    pixel.Y = (relativeLocation.Y/ bounds.Height) * aspectHeight;

                    if (idx == 0)
                    {
                        pf.StartPoint = pixel;
                    }
                    else
                    {
                        var ls = new LineSegment { Point = pixel };
                        pf.Segments.Add(ls);
                    }
                    idx++;
                }

                pf.IsClosed = Locations[0] == Locations[Locations.Count - 1];
                pathData.Figures.Add(pf);

                this.PathData = pathData;
            }
        }
        private void DetermineBounds()
        {
            bounds = new LocationRectangle(this.Locations);
        }

    }
}
